package com.xw.unification.entity;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Controller Mapping 工具类
 *
 * @author qiwei
 * @date 2023-8-9 21:00:00
 * @since v1.0.0
 */
public class ControllerMappingUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerMappingUtil.class);

    private static boolean init = false;
    private static boolean initMapping = false;
    private static RequestMappingHandlerMapping requestMappingHandlerMapping;
    private static final Map<Method, ControllerMapping> CONTROLLER_METHOD_MAPPING = new ConcurrentHashMap<>();
    private static final Map<Class<?>, List<Method>> CONTROLLER_CLASS_METHOD_MAPPING = new ConcurrentHashMap<>();

    public static synchronized void init(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        if (!init) {
            if (requestMappingHandlerMapping == null) {
                throw new IllegalArgumentException("RequestMappingHandlerMapping can not be null");
            } else {
                init = true;
                ControllerMappingUtil.requestMappingHandlerMapping = requestMappingHandlerMapping;
                return;
            }
        }
        throw new IllegalStateException("ControllerMappingUtil has been initialized");
    }

    public static synchronized void tryInit(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        if (!init) {
            if (requestMappingHandlerMapping == null) {
                throw new IllegalArgumentException("RequestMappingHandlerMapping can not be null");
            } else {
                init = true;
                ControllerMappingUtil.requestMappingHandlerMapping = requestMappingHandlerMapping;
            }
        }
    }

    public static synchronized void initMapping() {
        if (initMapping) {
            return;
        }
        checkInit();
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        HandlerMethod handlerMethod;
        for (RequestMappingInfo mappingInfo : handlerMethods.keySet()) {
            if (mappingInfo == null) {
                continue;
            }
            handlerMethod = handlerMethods.get(mappingInfo);
            if (handlerMethod == null) {
                continue;
            }
            Method method = handlerMethod.getMethod();
            CONTROLLER_METHOD_MAPPING.put(method, new ControllerMapping(handlerMethod, mappingInfo));
            List<Method> methodList = CONTROLLER_CLASS_METHOD_MAPPING.getOrDefault(method.getDeclaringClass(), new ArrayList<>());
            methodList.add(method);
            CONTROLLER_CLASS_METHOD_MAPPING.put(method.getDeclaringClass(), methodList);
        }
        initMapping = true;
    }

    public static ControllerMapping mappingMethod(Method method) {
        return CONTROLLER_METHOD_MAPPING.get(method);
    }

    public static Map<Method, ControllerMapping> mappingClass(Class<?> type) {
        List<Method> methods = CONTROLLER_CLASS_METHOD_MAPPING.getOrDefault(type, Collections.emptyList());
        Map<Method, ControllerMapping> mappingMap = new HashMap<>(methods.size());
        ControllerMapping controllerMapping;
        for (Method method : methods) {
            if (method == null) {
                continue;
            }
            controllerMapping = CONTROLLER_METHOD_MAPPING.get(method);
            if (controllerMapping == null) {
                continue;
            }
            mappingMap.put(method, controllerMapping);
        }
        return mappingMap;
    }

    private static void checkInit() {
        if (!init || requestMappingHandlerMapping == null) {
            throw new IllegalStateException("ControllerMappingUtil has not been initialized");
        }
    }
}
